window.showLoading = function (visible) {
  var id = 'global-loading'
  var div = document.getElementById(id)
  if (!div) {
    var html = '<div>'
    for (var i = 0; i < 8; i++) html += '<span></span>'
    html += '</div>'
    div = document.createElement('div')
    div.innerHTML = html
    div.id = id
    div.className = id
    div.style.display = 'none'
    document.body.appendChild(div)
  }
  div.style.display = visible ? 'block' : 'none'
}

window.uuid = function (hyphenation) {
  var array = [];
  var hex = "0123456789abcdef";
  for (var i = 0; i < 36; i++) array[i] = hex.substr(Math.floor(Math.random() * 16), 1);
  array[14] = "4";
  array[19] = hex.substr((array[19] & 0x3) | 0x8, 1);
  array[8] = array[13] = array[18] = array[23] = "-";
  var result = array.join("");
  if (hyphenation !== true) result = result.replace(/-/gm, "");
  return result;
};

// 显示吐司提示。
// _html：要显示的内容。
// _duration：持续时间，单位毫秒，不指定时默认 2000 毫秒。
window.toast = function (_html, _duration) {
  if (document.getElementsByClassName) {
    var shown = document.getElementsByClassName('elivo.toast')
    for (i = 0; i < shown.length; i++) {
      try {
        document.body.removeChild(shown[i])
      } catch (error) { }
    }
  }
  if (typeof _html != 'string' || _html == '') return

  var box = document.createElement('span')
  var area = document.createElement('div')
  console.info('elivo.toast', _html)
  box.style.backdropFilter = 'blur(5px)'
  box.style.backgroundColor = '#3f3f3f'
  box.style.borderRadius = '5px'
  box.style.boxShadow = '0px 10px 40px rgba(0,0,0, 0.3)'
  box.style.color = 'white'
  box.style.display = 'inline-block'
  box.style.fontFamily = "consolas, 'microsoft yahei', 'pingfang sc', sans-serif"
  box.style.fontSize = '14px'
  box.style.lineHeight = '28px'
  box.style.paddingBottom = '10px'
  box.style.paddingLeft = '20px'
  box.style.paddingRight = '20px'
  box.style.paddingTop = '10px'
  box.style.textShadow = '0px 0px 10px rgba(0,0,0, 0.5)'
  box.innerHTML = _html
  area.className = 'elivo.toast'
  area.style.bottom = '20%'
  area.style.display = 'block'
  area.style.fontSize = '0px'
  area.style.left = '10%'
  area.style.opacity = '0'
  area.style.position = 'fixed'
  area.style.right = '10%'
  area.style.textAlign = 'center'
  area.style.transition = 'all 0.15s linear'
  area.style.zIndex = '200000000'
  area.appendChild(box)
  document.body.appendChild(area)
  setTimeout(function () {
    area.style.opacity = 1
    var delay = 150 + parseInt(typeof _duration == 'number' ? _duration : 2000)
    setTimeout(function () {
      area.style.opacity = 0
      setTimeout(function () {
        try {
          document.body.removeChild(area)
        } catch (error) { }
      }, 300)
    }, delay)
  }, 1)
  return { area: area, box: box }
};

// ajax
(function () {
  function _receive(xhr, succeed, failed) {
    xhr.onreadystatechange = () => {
      if (xhr.readyState != 4) return
      var response = xhr.responseText
      try {
        var json = JSON.parse(response)
        response = json
      } catch (err) {
        console.error('ajax', err.message)
      }
      if (xhr.status == 200 || xhr.status == 304) {
        if (typeof succeed === 'function') succeed(response)
      } else {
        if (typeof failed === 'function') failed(response)
      }
    }
  }

  window.ajaxGet = function (url, succeed, failed) {
    var xhr = new XMLHttpRequest();
    xhr.timeout = 300000;
    xhr.open('GET', url, true);
    var jwt = localStorage.getItem("AccountJwt");
    if (jwt) xhr.setRequestHeader('Jwt', jwt);
    _receive(xhr, succeed, failed);
    var languageCodes = getLanguageCodes();
    if (languageCodes) {
        xhr.setRequestHeader('Language-Codes', languageCodes);
    }
    try {
      xhr.send();
    } catch (err) {
      console.error("ajaxGet", xhr, url, err);
      if (typeof failed === 'function') failed(err.message);
    }
  }

  window.ajaxPost = function (url, data, succeed, failed) {
    var content = '';
    if (data) {
      if (typeof data == 'string') content = data;
      else if (typeof data == 'object') content = JSON.stringify(data);
      else content = String(data);
    } else {
      data = "";
    }

    var xhr = new XMLHttpRequest()
    xhr.timeout = 300000;
    xhr.open('POST', url, true);
    xhr.setRequestHeader('Content-Type', 'text/plain');
    var jwt = localStorage.getItem("AccountJwt");
    if (jwt) xhr.setRequestHeader('Jwt', jwt);
    _receive(xhr, succeed, failed);
    var languageCodes = getLanguageCodes();
    if (languageCodes) {
        xhr.setRequestHeader('Language-Codes', languageCodes);
    }
    try {
      xhr.send(content);
    } catch (err) {
      console.error("ajaxPost", xhr, url, data, err);
      if (typeof failed === 'function') failed(err.message);
    }
  }

  window.ajaxUpload = function (url, succeed, failed, accept, before, after, progress, _blob) {
    if (typeof succeed != "function") succeed = function () { };
    if (typeof failed != "function") failed = function (msg) { console.error("ajaxUpload", msg); };
    if (typeof before != "function") before = function (file) { console.log("ajaxUpload", "before", file); };
    if (typeof after != "function") after = function (file) { console.log("ajaxUpload", "after", file); };
    if (typeof progress != "function") progress = function (p) { console.log("ajaxUpload", "progress", p); };
    if (!url) return failed("未指定 URL。");

    var input = document.createElement("input");
    input.type = "file";
    if (accept && typeof accept == "string") input.accept = accept;
    input.click();
    input.onchange = function (evt) {
      if (evt.target.files.length < 1) return failed("没有选择文件。");

      if (typeof url == "function") url = url(evt.target.files[0]);
      if (typeof url != "string") return failed("未获取 URL。");

      var file = evt.target.files[0];
      if (typeof before == "function") {
        var value = before(file);
        if (typeof value == "boolean" && value == false) return;
        if (typeof value == "number" && value == 0) return;
      }

      var reader = new FileReader();
      reader.file = file;
      reader.onabort = function (e) { };
      reader.onerror = function (e) { };
      reader.onloadstart = function (e) { };
      reader.onprogress = function (e) { };
      reader.onload = function (e) { };
      reader.onloadend = function (e) {
        var xhr = new XMLHttpRequest();
        xhr.open("post", url);
        xhr.setRequestHeader("Content-Type", "application/octet-stream");
        var jwt = localStorage.getItem("AccountJwt");
        if (jwt) xhr.setRequestHeader('Jwt', jwt);
        var languageCodes = getLanguageCodes();
        if (languageCodes) {
            xhr.setRequestHeader('Language-Codes', languageCodes);
        }
        if (_blob) xhr.responseType = 'arraybuffer';
        xhr.onreadystatechange = function (e) {
          if (xhr.readyState == 4) {
            after(file);
            if (xhr.status == 200) {
              if (_blob) {
                var blob = new Blob([xhr.response]);
                if (typeof _succeed === 'function') _succeed(blob);
                return;
              }
              var response = xhr.responseText;
              try { response = JSON.parse(response); } catch (err) { }
              succeed(response);
            } else failed("Status=" + String(xhr.status));
          }
        };
        xhr.onprogress = function (e) {
          if (e.lengthComputable) {
            var p = { name: reader.file.name, total: e.total, loaded: e.loaded };
            progress(p);
          }
        };
        try {
          xhr.send(reader.result);
        } catch (err) {
          console.error("ajaxUpload", xhr, url, data, err);
          if (typeof failed === 'function') failed(err.message);
        }

      };
      reader.readAsArrayBuffer(file);
    };
  };

  window.eapGet = function (urlPath, succeed, failed) {
    if (!urlPath || typeof urlPath != "string") return;
    while (urlPath && urlPath.substring(0, 1) == "/") urlPath = urlPath.substring(1);
    var url = "http://" + window.location.hostname + ":8093/" + urlPath;
    var xhr = new XMLHttpRequest();
    xhr.timeout = 300000;
    xhr.open('GET', url, true);
    _receive(xhr, succeed, failed);
    try {
      xhr.send();
    } catch (err) {
      console.error("ajaxGet", xhr, url, err);
      if (typeof failed === 'function') failed(err.message);
    }
  };

  window.eapPost = function (urlPath, data, succeed, failed) {
    if (!urlPath || typeof urlPath != "string") return;
    while (urlPath && urlPath.substring(0, 1) == "/") urlPath = urlPath.substring(1);
    var url = "http://" + window.location.hostname + ":8093/" + urlPath;

    var content = '';
    if (data) {
      if (typeof data == 'string') content = data;
      else if (typeof data == 'object') content = JSON.stringify(data);
      else content = String(data);
    } else {
      data = "";
    }

    var xhr = new XMLHttpRequest()
    xhr.timeout = 300000;
    xhr.open('POST', url, true);
    xhr.setRequestHeader('Content-Type', 'text/plain');
    _receive(xhr, succeed, failed);
    try {
      xhr.send(content);
    } catch (err) {
      console.error("ajaxPost", xhr, url, data, err);
      if (typeof failed === 'function') failed(err.message);
    }
  };

})();

// 从指定字符串中获取参数。
window.urlQuery = function (selector, decode) {
  var combined = window.location.search
  if (!combined) return ''
  switch (typeof selector) {
    case 'string':
    case 'number':
      break
    default:
      return ''
  }
  var matched = combined.match(new RegExp('[?&#][^?&]+=[^?&]+', 'g'))
  var array = []
  if (matched) {
    for (var i = 0; i < matched.length; i++) {
      var split = matched[i].substring(1).split('=')
      array.push({ key: split[0], value: split[1] })
    }
  }
  var value = ''
  switch (typeof selector) {
    case 'string':
      for (var i in array) {
        if (array[i].key == selector) {
          value = array[i].value
          break
        }
      }
      break
    case 'number':
      var i = parseInt(selector)
      if (i >= 0 && i < array.length) {
        value = array[i].value
        break
      }
      break
  }
  if (decode) value = decodeURIComponent(value)
  return value
};

window.toLucid = window.lucidDate = function (date) {
  if (typeof date === 'number' || typeof date === 'string') return lucidDate(new Date(date))
  if (date && date instanceof Date) {
    var year = date.getFullYear()
    var month = date.getMonth() + 1
    var day = date.getDate()
    var hour = date.getHours()
    var minute = date.getMinutes()
    var second = date.getSeconds()
    var milli = date.getMilliseconds()
    year = (year < 10 ? '000' : year < 100 ? '00' : year < 1000 ? '0' : '') + String(year)
    month = (month < 10 ? '0' : '') + String(month)
    day = (day < 10 ? '0' : '') + String(day)
    hour = (hour < 10 ? '0' : '') + String(hour)
    minute = (minute < 10 ? '0' : '') + String(minute)
    second = (second < 10 ? '0' : '') + String(second)
    milli = (milli < 10 ? '00' : milli < 100 ? '0' : '') + String(milli)
    return year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second; //  + '.' + milli
  }
  if (date && date._d instanceof Date) return lucidDate(date._d);
  return '';
};

// IndexedDB
(function () {
  window.IDB = function (dbName, tableName, keyField) {
    var _dbName = dbName
    var _tableName = tableName
    var _keyField = 'id'

    if (!dbName) throw '参数 dbName 无效。'
    if (!tableName) throw '参数 tableName 无效。'
    if (keyField) _keyField = keyField

    window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB
    window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction
    window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange

    function onupgradeneeded (event) {
      var db = event.target.result
      var objectStore
      if (!db.objectStoreNames.contains(_tableName)) {
        objectStore = db.createObjectStore(_tableName, { keyPath: _keyField })
      }
    }

    function isArray (value) {
      if (typeof Array.isArray === 'function') {
        return Array.isArray(value)
      } else {
        return Object.prototype.toString.call(value) === '[object Array]'
      }
    }

    function canAsync () {
      var userAgent = (userAgent || navigator.userAgent).toLowerCase()
      var isEdge = /\sedge\//.test(userAgent)
      var version = isEdge ? (userAgent.match(/(?:edge\/)([\d\.]*)/) || [])[1] : (userAgent.match(/.*(?:rv|chrome|webkit|opera|ie)[\/: ](.+?)([ \);]|$)/) || [])[1]
      var webkitVersion = (userAgent.match(/webkit\/(.+?) /) || [])[1]
      var webkit = (!isEdge && /webkit/.test(userAgent)) ? webkitVersion : ''
      var chrome = !isEdge && /chrome/.test(userAgent) ? version : ''
      var version = parseInt(chrome.split('.')[0])
      if (isNaN(version) || !isFinite(version)) version = 0
      return version >= 54
    }

    function idbSet (record, callback) {
      if (!record) {
        console.error('idb', 'invalid item', record)
        return
      }

      var key = record[_keyField]
      if (typeof key !== 'number' && !key) {
        console.error('idb', 'invalid ' + String(_keyField), record)
        return
      }

      var open = indexedDB.open(_dbName, 1)
      open.onerror = function (event) {
        console.error('idb.open', event)
      }
      open.onupgradeneeded = onupgradeneeded
      open.onsuccess = function (event) {
        var db = event.target.result
        var transaction = db.transaction(_tableName, 'readwrite')
        var store = transaction.objectStore(_tableName)
        var getRequest = store.get(key)
        getRequest.onerror = function (event) {
          console.error('idb.get', event)
          transaction.abort()
          db.close()
        }
        getRequest.onsuccess = function (event) {
          var value = event.target.result
          if (value) {
            var putRequest = store.put(record)
            putRequest.onerror = function (event) {
              console.log('idb.put.error', event)
              transaction.abort()
              db.close()
            }
            putRequest.onsuccess = function (event) {
              transaction.commit()
              db.close()
              if (typeof callback === 'function') callback()
            }
          } else {
            var addRequest = store.add(record)
            addRequest.onerror = function (event) {
              console.log('idb.add.error', event)
              transaction.abort()
              db.close()
            }
            addRequest.onsuccess = function (event) {
              transaction.commit()
              db.close()
              if (typeof callback === 'function') callback()
            }
          }
        }
      }
    }

    function idbGet (key, callback) {
      var openRequest = indexedDB.open(_dbName, 1)
      openRequest.onerror = function (event) {
        console.error('idb.open', event)
      }
      openRequest.onupgradeneeded = onupgradeneeded
      openRequest.onsuccess = function (event) {
        var db = event.target.result
        var transaction = db.transaction(_tableName, 'readonly')
        var store = transaction.objectStore(_tableName)
        var getRequest = store.get(key)
        getRequest.onerror = function (event) {
          console.error('idb.get', event)
          transaction.abort()
          db.close()
        }
        getRequest.onsuccess = function (event) {
          var value = event.target.result
          transaction.abort()
          db.close()
          if (typeof callback === 'function') callback(value)
        }
      }
    }

    function idbAll (callback) {
      var openRequest = indexedDB.open(_dbName, 1)
      openRequest.onerror = function (event) {
        console.error('idb.open', event)
      }
      openRequest.onupgradeneeded = onupgradeneeded
      openRequest.onsuccess = function (event) {
        var db = event.target.result
        var array = []
        var transaction = db.transaction(_tableName, 'readonly')
        var store = transaction.objectStore(_tableName)
        var getAllRequest = store.getAll()
        getAllRequest.onsuccess = function (event) {
          var result = event.target.result
          if (!result) result = []
          transaction.abort()
          db.close()
          if (typeof callback === 'function') callback(array)
        }
      }
    }

    function idbDelete (key, callback) {
      if (typeof key !== 'number' && !key) {
        console.error('idb.delete', 'invalid ' + String(_keyField), key)
        return
      }

      var open = indexedDB.open(_dbName, 1)
      open.onerror = function (event) {
        console.error('idb.open', event)
      }
      open.onupgradeneeded = onupgradeneeded
      open.onsuccess = function (event) {
        var db = event.target.result
        var transaction = db.transaction(_tableName, 'readwrite')
        var store = transaction.objectStore(_tableName)
        var deleteRequest = store.delete(key)
        deleteRequest.onerror = function (event) {
          console.error('idb.delete', event)
          transaction.abort()
          db.close()
        }
        deleteRequest.onsuccess = function (event) {
          transaction.commit()
          db.close()
          if (typeof callback === 'function') callback()
        }
      }
    }

    return { add: idbSet, all: idbAll, delete: idbDelete, get: idbGet, set: idbSet }
  }
})();

// Lang
(function () {
  window.getLanguageCodes = function () {
    var value = localStorage.getItem('language')
    if (!value) value = localStorage.getItem('language-codes')
    if (!value) value = ''
    var length = value.length
    if (length >= 2 && value.substring(0, 1) == '"' && value.substring(length - 1) == '"') value = substring(1, length - 2)
    return value
  }

  window._strings = []

  function loadStrings (callback, force) {
    if (!force && window._strings && window._strings.length) {
      if (typeof callback === 'function') callback(_strings)
      return 1
    }
    ajaxGet('/api/oneLanguage/listStrings', (r) => {
      if (r.Data && r.Data.length) {
        if (r.Data && r.Data.length) {
          var idb = new IDB('lang', 'strings')
          for (var i = 0; i < r.Data.length; i++) {
            if (r.Data[i]) idb.set(r.Data[i])
          }
          window._strings = r.Data
          if (typeof callback === 'function') callback(window._strings)
        }
        return 1
      }
      setTimeout(() => {
        loadStrings(callback, force)
      }, 2000)
    }, (e) => {
      setTimeout(() => {
        loadStrings(callback, force)
      }, 2000)
    })
  }

  function getStrings (id, chinese, args, skip) {
    var argsArray = []
    if (typeof skip !== 'number') skip = 0
    for (var i = skip; i < args.length; i++) argsArray.push(args[i])
    args = argsArray

    // ID 无效
    var array = []
    if (id < 1) {
      array.push('invalid id')
      return array
    }

    // 加载字典，获取字典条目
    var record = null
    if (window._strings != null && window._strings.length > 0) {
      for (var i = 0; i < window._strings.length; i++) {
        if (window._strings[i].Id == id) {
          record = window._strings[i]
          break
        }
      }
    }

    // 无字典条目，且未指定中文
    if (!record) {
      if (!chinese || typeof chinese !== 'string') {
        array.push('untranslated')
        return array
      }
    }

    // 准备
    var codes = []
    var split = window.getLanguageCodes().split(',')
    for (var i = 0; i < split.length; i++) {
      var code = split[i].trim()
      if (code) codes.push(code)
    }
    if (!codes.length) codes.push('Zh')
    // 获取翻译后的文本
    var values = []
    if (record) {
      for (var i = 0; i < codes.length; i++) {
        var value = record[codes[i]]
        if (!value) value = ''
        values.push(value)
      }
    } else {
      values.push(chinese)
    }

    // 读取变量的值
    var vars = []
    for (var i = 0; i < args.length; i++) {
      function getVar (arg, recurve) {
        if (arg == null) return ''
        switch (typeof arg) {
          case 'boolean':
          case 'number':
            return String(arg)
          case 'string':
            return arg || ''
          case 'function':
            if (recurve > 2) return String(arg)
            return getVar(arg(), recurve + 1)
        }
        return String(arg)
      }

      vars.push(getVar(args[i]))
    }

    // 将变量加入翻译后的文本
    if (vars.length) {
      for (var j = 0; j < values.length; j++) {
        var value = values[j]
        if (!value) continue
        var i = 0
        var e = 0
        while (e < 10) {
          var o = '{' + String(i) + '}'
          var r = false
          while (value.indexOf(o) > -1) {
            value = value.replace(o, i < vars.length ? vars[i] : '')
            r = true
          }
          e = r ? 0 : (e + 1)
          i++
        }
        values[j] = value
      }
    }

    return values
  }

  // 获取首选语言的文本。
  function first (id, vars) {
    var strs = getStrings(id, '', arguments, 1)
    return strs[0]
  }

  // 获取第二语言的文本。
  function second (id, vars) {
    var strs = getStrings(id, '', arguments, 1)
    return strs.length > 1 ? strs[1] : ''
  }

  function duo (id, vars) {
    var strs = getStrings(id, '', arguments, 1)
    var text = '<span'
    if (strs.length > 1) {
      text += ' title="'
      text += strs[1].replace(/\"/gm, '\\"')
      text += '"'
    }
    text += '>'
    text += strs[0]
    text += '</span>'
    return text
  }

  // 获取多语言的文本，每行一种。
  function line (id, vars) {
    var strs = getStrings(id, '', arguments, 1)
    return strs.join('\r\n')
  }

  // 获取多语言的文本， 使用()分隔
  function brackets (id, vars) {
    var strs = getStrings(id, '', arguments, 1)
    if (strs.length > 1) {
      // return strs[0] + '(' + strs[1] + ')';
      return strs.join('(') + ')'
    } else {
      return strs
    }
  }

  // 分隔符
  function separator (id, vars) {
    var strs = getStrings(id, '', arguments, 1)
    if (strs.length > 1) {
      return strs.join('|')
    } else {
      if(Object.prototype.toString.call(strs) === '[object Array]')
      {
        strs = strs[0]
      }
      return strs
    }
  }

  // 获取多语言的文本，使用 <br> 分隔。
  function br (id, vars) {
    var strs = getStrings(id, '', arguments, 1)
    return strs.join('<br>')
  }

  // 获取多语言的文本，使用 SPAN 标签包含每种语言。
  function span (id, vars) {
    var strs = getStrings(id, '', arguments, 1)
    return '<span>' + strs.join('</span><span>') + '</span>'
  }

  // 获取多语言的文本，使用 DIV 标签包含每种语言。
  function div (id, vars) {
    var strs = getStrings(id, '', arguments, 1)
    return '<div>' + strs.join('</div><div>') + '</div>'
  }

  // 获取首选语言的文本。
  function first2 (id, chinese, vars) {
    var strs = getStrings(id, chinese, arguments, 2)
    return strs[0]
  }

  // 获取第二语言的文本。
  function second2 (id, chinese, vars) {
    var strs = getStrings(id, chinese, arguments, 2)
    return strs.length > 1 ? strs[1] : ''
  }

  function duo2 (id, chinese, vars) {
    var strs = getStrings(id, chinese, arguments, 2)
    var text = '<span'
    if (strs.length > 1) {
      text += ' title="'
      text += strs[1].replace(/\"/gm, '\\"')
      text += '"'
    }
    text += '>'
    text += strs[0]
    text += '</span>'
    return text
  }

  // 获取多语言的文本，每行一种。
  function line2 (id, chinese, vars) {
    var strs = getStrings(id, chinese, arguments, 2)
    return strs.join('\r\n')
  }

  // 获取多语言的文本， 使用()分隔
  function brackets2 (id, chinese, vars) {
    var strs = getStrings(id, chinese, arguments, 2)
    if (strs.length > 1) {
      // return strs[0] + '(' + strs[1] + ')';
      return strs.join('(') + ')'
    } else {
      return strs
    }
  }

  // 获取多语言的文本，使用 <br> 分隔。
  function br2 (id, chinese, vars) {
    var strs = getStrings(id, chinese, arguments, 2)
    return strs.join('<br>')
  }

  // 获取多语言的文本，使用 SPAN 标签包含每种语言。
  function span2 (id, chinese, vars) {
    var strs = getStrings(id, chinese, arguments, 2)
    return '<span>' + strs.join('</span><span>') + '</span>'
  }

  // 获取多语言的文本，使用 DIV 标签包含每种语言。
  function div2 (id, chinese, vars) {
    var strs = getStrings(id, chinese, arguments, 2)
    return '<div>' + strs.join('</div><div>') + '</div>'
  }

  // 根据id，默认中文，获取 中文|English 样式文字
  function separator2 (id, chinese, vars) {
    var strs = getStrings(id, chinese, arguments, 2)
    if (strs.length > 1) {
      return strs.join('|')
    } else {
      if(Object.prototype.toString.call(strs) === '[object Array]')
      {
        strs = strs[0]
      }
      return strs
    }
  }

  window.lang = {
    importDictXlsx: function () {
      ajaxUpload('/api/oneLanguage/importDictXlsx', function (r) {
        console.log('importDictXlsx', 'succeed', r)
      }, function (e) {
        console.log('importDictXlsx', 'failed', e)
      })
    },

    loadStrings: loadStrings,
    strings: function () {
      return window._strings
    },
    first: first,
    second: second,
    duo: duo,
    line: line,
    br: br,
    brackets: brackets,
    span: span,
    div: div,
    separator: separator,

    first2: first2,
    second2: second2,
    duo2: duo2,
    line2: line2,
    br2: br2,
    brackets2: brackets2,
    span2: span2,
    div2: div2,
    separator2: separator2
  }

  // 加载缓存的语言字典。
  new IDB('lang', 'strings').all(records => {
    if (records && records.length) window._strings = records
  })
})()

